#pragma once
#ifndef skyObject_h__
#define skyObject_h__

#include "./skyType.h"
#include "./skyRtti.h"
#include "./skyPtr.h"

namespace Sky
{



	//////////////////////////////////////////////////////////////////////////
	class Memory
	{
	public:
		static i32 alloc_count;
		static i32 free_count;
	public:
		static Void* alloc(size_t size);
		static Void* realloc(Void* p,size_t size);
		static Void  free(Void* p);
		static Void  copy(Void* dst,const Void* src,size_t size);
		static Void  set(Void* dst,u32 n,size_t size);
		static Void* clone(size_t size,const Void* src);
		Void* operator new(unsigned int size);                              
		Void  operator delete(Void* p);                                   
		Void* operator new[](unsigned int size);                                   
		Void  operator delete[](Void* p);
	};
	//////////////////////////////////////////////////////////////////////////
	template <typename CLS>
	class AutoPtr
	{
	public:
		typedef CLS type;
		CLS* ptr;
	public:
		AutoPtr(){}
		AutoPtr(CLS * p){ptr = p;}
		~AutoPtr(){if(ptr)delete ptr;}
	};
	//////////////////////////////////////////////////////////////////////////
	class RefObject : public Memory
	{
	public:
		virtual Void incRef(){};
		virtual Void decRef(){};
	};
	class Object;
	class PtrWrapper
	{
	protected:
		RefObject* ptr;
	public:
		PtrWrapper():ptr(vNull){}
		~PtrWrapper();
	public:
		RefObject* leakPtr(){return ptr;}

	};
	template <typename CLS>
	class RefPtr : public PtrWrapper
	{
	public:
		typedef CLS type;
	public:
		RefPtr(){}

		RefPtr(CLS* p);
		
		RefPtr(RefPtr& rref)
		{
			if(rref)rref->incRef();
			if(ptr)ptr->decRef();
			ptr = rref.leakPtr();
		}
		
		template <typename CLS2>
		RefPtr(CLS2* rref)
		{
			if(rref)rref->incRef();
			if(ptr)ptr->decRef();
			ptr = rref;
		}
		
		~RefPtr(){}

		template <typename CLS2>
		RefPtr( RefPtr<CLS2>& rref )
		{
			if(rref)rref->incRef();
			if(ptr)ptr->decRef();
			ptr = rref.leakPtr();
		}
		
		void operator = (CLS* p);
		
		void operator = (RefPtr& p)
		{
			p->incRef();
			if(ptr)ptr->decRef();
			ptr = p.leakPtr();
		}
		
		CLS* operator ->();

		CLS* leakPtr();

		operator CLS* () { return leakPtr(); }

	};
	class String;
	typedef RefPtr<String> StringPtr;
	class Object : public RefObject
	{
		friend class sky_new;
		DECL_RTTI0(Object);
	public:		

		Object();
		Bool isOnHeap(){return _ref != (i32)0x80000000;}
		virtual Void incRef();
		virtual Void decRef();
		virtual ~Object();
		virtual StringPtr toString(StringPtr str = StringPtr());
	protected:
		i32 _ref;
	};
	typedef RefPtr<Object> ObjectPtr;

	//////////////////////////////////////////////////////////////////////////
	class sky_new
	{
	public:
		template <typename T>
		static RefPtr<T> skynew_tap(T* p)
		{
			p->_ref = 0;
			return RefPtr<T>(p);
		}
	};

	template <typename CLS>
	void RefPtr<CLS>::operator=( CLS* p )
	{
		if(p)p->incRef();
		if(ptr)ptr->decRef();
		ptr = p;
	}


	template <typename CLS>
	CLS* RefPtr<CLS>::operator->()
	{
		return leakPtr();
	}


	template <typename CLS>
	CLS* RefPtr<CLS>::leakPtr()
	{
		return (CLS*)PtrWrapper::leakPtr();
	}

	//	template <typename CLS>
//	RefPtr<CLS>::RefPtr( RefPtr& r )
//	{
//		if(r)r->incRef();
//		if(ptr)ptr->decRef();
//		ptr = r;
//	}

	template <typename CLS>
	RefPtr<CLS>::RefPtr( CLS* p )
	{
		if(p)p->incRef();
		if(ptr)ptr->decRef();
		ptr = p;
	}
#define skynew(obj) sky_new::skynew_tap(new obj)

	
}

#endif // skyObject_h__
